home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / pc / MASM.ZIP / SAMPLES / DEMOS / MISC.AS$ / MISC.bin
Encoding:
Text File  |  1991-02-14  |  38.2 KB  |  1,000 lines

  1.         .modeL  small, pascal, os_dos
  2.         INCLUDE demo.inc
  3.  
  4.         .DATA
  5. _psp    PSEG    ?               ; Segment of PSP
  6. _env    PSEG    ?               ; Segment of environment
  7.  
  8.         .CODE
  9.  
  10. ;* WinOpen - Saves portion of screen to allocated memory, then opens a window
  11. ;* with specified fill attribute. See also the WinClose procedure.
  12. ;*
  13. ;* Shows:   DOS Function - 48h (Allocate Memory Block)
  14. ;*          Instructions - movsw      stosw     rep
  15. ;*
  16. ;* Uses:    vconfig - Video configuration structure (initialized
  17. ;*          by calling the GetVidConfig procedure)
  18. ;*
  19. ;* Params:  Row1 - Row at top of window
  20. ;*          Col1 - Column at left edge of window
  21. ;*          Row2 - Row at bottom of window
  22. ;*          Col2 - Column at right edge of window
  23. ;*          Attr - Fill attribute for window
  24. ;*
  25. ;* Return:  Short integer with segment address of allocated buffer, or
  26. ;*          0 if unable to allocate memory
  27.  
  28. WinOpen PROC USES ds di si,
  29.         Row1:WORD, Col1:WORD, Row2:WORD, Col2:WORD, Attr:WORD
  30.  
  31.         GetVidOffset Row1, Col1         ; Get offset in video segment
  32.         mov     si, ax                  ; SI = video offset for window
  33.         mov     bx, Row2
  34.         sub     bx, Row1
  35.         inc     bx                      ; BX = number of window rows
  36.         mov     cx, Col2
  37.         sub     cx, Col1
  38.         inc     cx                      ; CX = number of columns
  39.  
  40.         mov     ax, cx                  ; Compute number of video
  41.         mul     bl                      ;   cells in window
  42.         add     ax, 3                   ; Plus 3 additional entries
  43.         shr     ax, 1                   ; Shift right 3 times to
  44.         shr     ax, 1                   ;   multiply by 2 bytes/cell,
  45.         shr     ax, 1                   ;   divide by 16 bytes/paragraph
  46.         inc     ax                      ; Add a paragraph
  47.         push    bx                      ; Save number of rows
  48.         mov     bx, ax                  ; BX = number of paragraphs
  49.         mov     ah, 48h                 ; Request DOS Function 48h
  50.         int     21h                     ; Allocate Memory Block
  51.         pop     bx
  52.  
  53.         .IF     carry?                  ; If unsuccessful,
  54.         sub     ax, ax                  ;   return null pointer
  55.         .ELSE
  56.         mov     es, ax                  ; Point ES:DI to allocated
  57.         sub     di, di                  ;   buffer
  58.         mov     ax, si
  59.         stosw                           ; Copy video offset to buffer
  60.         mov     ax, bx
  61.         stosw                           ; Number of rows to buffer
  62.         mov     ax, cx
  63.         stosw                           ; Number of cols to buffer
  64.         mov     ax, 160                 ; Number of video cells/row
  65.         mov     ds, vconfig.sgmnt       ; DS = video segment
  66.  
  67.         .REPEAT
  68.         push    si                      ; Save ptr to start of line
  69.         push    cx                      ;   and number of columns
  70.  
  71. ; For CGA adapters, WinOpen avoids screen "snow" by disabling the video prior
  72. ; to block memory moves, then reenabling it. Although this technique can
  73. ; result in brief flickering, it demonstrates the fastest way to access a
  74. ; block in the CGA video buffer without causing display snow. See also the
  75. ; StrWrite procedure for another solution to the problem of CGA snow.
  76.  
  77.         .IF     vconfig.adapter == CGA  ; If not CGA adapter,
  78.         INVOKE  DisableCga              ;   disable video
  79.         .ENDIF
  80.  
  81.         rep     movsw                   ; Copy one row to buffer
  82.  
  83.         .IF     vconfig.adapter == CGA  ; If CGA adapter,
  84.         INVOKE  EnableCga               ;   reenable CGA video
  85.         .ENDIF
  86.         pop     cx                      ; Recover number of columns
  87.         pop     si                      ;   and start of line
  88.         add     si, ax                  ; Point to start of next line
  89.         dec     bx                      ; Decrement row counter
  90.         .UNTIL  zero?                   ; Until no rows remain
  91.  
  92. ; Screen contents (including display attributes) are now copied to buffer.
  93. ; Next open window, overwriting the screen portion just saved.
  94.  
  95.         mov     ax, 0600h               ; Scroll service
  96.         mov     bh, BYTE PTR Attr       ; Fill attribute
  97.         mov     cx, Col1                ; CX = row/col for upper left
  98.         mov     ch, BYTE PTR Row1
  99.         mov     dx, Col2                ; DX = row/col for lower right
  100.         mov     dh, BYTE PTR Row2
  101.         int     10h                     ; Blank window area on screen
  102.         mov     ax, es                  ; Return address of allocated
  103.         .ENDIF                          ;   segment
  104.         ret
  105.  
  106. WinOpen ENDP
  107.  
  108.  
  109. ;* WinClose - "Closes" a window previously opened by the WinOpen procedure.
  110. ;* See also the WinOpen procedure.
  111. ;*
  112. ;* Shows:   DOS Function - 49h (Release Memory Block)
  113. ;*          Instructions - lodsw
  114. ;*          Operators - : (segment override)     SEG
  115. ;*
  116. ;* Uses:    vconfig - Video configuration structure (initialized
  117. ;*          by calling the GetVidConfig procedure)
  118. ;*
  119. ;* Params:  Adr - Segment address of buffer that holds screen contents
  120. ;*                saved in WinOpen procedure
  121. ;*
  122. ;* Return:  None
  123.  
  124. WinClose PROC USES ds di si,
  125.         Adr:WORD
  126.  
  127.         mov     ds, Adr                 ; DS:SI points to buffer
  128.         sub     si, si
  129.         lodsw
  130.         mov     di, ax                  ; DI = video offset of window
  131.         lodsw
  132.         mov     bx, ax                  ; BX = number of window rows
  133.         lodsw
  134.         mov     cx, ax                  ; CX = number of columns
  135.  
  136.         mov     ax, SEG vconfig.sgmnt
  137.         mov     es, ax                  ; Point ES to data segment
  138.         push    es:vconfig.sgmnt
  139.         pop     es                      ; ES = video segment
  140.         mov     ax, 160                 ; Number of video cells/row
  141.  
  142.         .REPEAT
  143.         push    di                      ; Save ptr to start of line
  144.         push    cx                      ;   and number of columns
  145.  
  146. ; Disable CGA video prior to memory move to avoid screen snow. (See the
  147. ; WinOpen and StrWrite procedures for further discussions on CGA snow.)
  148.  
  149.         .IF     vconfig.adapter == CGA  ; If CGA adapter,
  150.         INVOKE  DisableCga              ;   disable video
  151.         .ENDIF
  152.  
  153.         rep     movsw                   ; Copy one row to buffer
  154.  
  155.         .IF     vconfig.adapter == CGA  ; If CGA adapter,
  156.         INVOKE  EnableCga               ;   reenable CGA video
  157.         .ENDIF
  158.         pop     cx                      ; Recover number of columns
  159.         pop     di                      ;   and start of line
  160.         add     di, ax                  ; Point to start of next line
  161.         dec     bx                      ; Decrement row counter
  162.         .UNTIL  zero?                   ;   until no rows remain
  163.  
  164.         mov     ah, 49h                 ; Request DOS Function 49h
  165.         mov     es, Adr
  166.         int     21h                     ; Release Memory Block
  167.         ret
  168.  
  169. WinClose ENDP
  170.  
  171.  
  172. ;* SetCurSize - Sets cursor size.
  173. ;*
  174. ;* Shows:   BIOS Interrupt - 10h, Function 1 (Set Cursor Type)
  175. ;*
  176. ;* Params:  Scan1 - Starting scan line
  177. ;*          Scan2 - Ending scan line
  178. ;*
  179. ;* Return:  None
  180.  
  181. SetCurSize PROC,
  182.         Scan1:WORD, Scan2:WORD
  183.  
  184.         mov     cx, Scan2               ; CL = ending scan line
  185.         mov     ch, BYTE PTR Scan1      ; CH = starting scan line
  186.         mov     ah, 1                   ; Function 1
  187.         int     10h                     ; Set Cursor Type
  188.         ret
  189.  
  190. SetCurSize ENDP
  191.  
  192.  
  193. ;* GetCurSize - Gets current cursor size.
  194. ;*
  195. ;* Shows:   BIOS Interrupt - 10h, Function 3 (Get Cursor Position)
  196. ;*
  197. ;* Uses:    vconfig - Video configuration structure (initialized
  198. ;*          by calling the GetVidConfig procedure)
  199. ;*
  200. ;* Params:  None
  201. ;*
  202. ;* Return:  Short integer with high byte = top scan line,
  203. ;*                             low byte  = bottom scan line
  204.  
  205. GetCurSize PROC
  206.  
  207.         mov     ah, 3                   ; Function 3
  208.         mov     bh, vconfig.dpage
  209.         int     10h                     ; Get Cursor Position
  210.         mov     ax, cx                  ; Return cursor size
  211.         ret
  212.  
  213. GetCurSize ENDP
  214.  
  215.  
  216. ;* GetShift - Gets current shift status. Checks for extended keyboard,
  217. ;* and, if available, returns additional shift information.
  218. ;*
  219. ;* Shows:   BIOS Interrupt - 16h, Functions 2 and 12h (Get Keyboard Flags)
  220. ;*
  221. ;* Params:  None
  222. ;*
  223. ;* Return:  Long integer
  224. ;*          high word = 0 for nonextended keyboard
  225. ;*                      1 for extended keyboard
  226. ;*          low word has following bits set when indicated keys are pressed:
  227. ;*          0 - Right SHIFT                   8 - Left CTRL
  228. ;*          1 - Left SHIFT                    9 - Left ALT
  229. ;*          2 - CTRL                         10 - Right CTRL
  230. ;*          3 - ALT                          11 - Right ALT
  231. ;*          4 - SCROLL LOCK active           12 - SCROLL LOCK pressed
  232. ;*          5 - NUM LOCK active              13 - NUM LOCK pressed
  233. ;*          6 - CAPS LOCK active             14 - CAPS LOCK pressed
  234. ;*          7 - INSERT toggled               15 - SYS REQ pressed
  235.  
  236. GetShift PROC
  237.  
  238.         sub     dx, dx                  ; Assume nonextended keyboard
  239.         mov     ah, 2                   ;   and use Function 2
  240.         mov     es, dx                  ; Point ES to low memory
  241.         .IF     BYTE PTR es:[496h] & 16 ; If extended keyboard installed,
  242.         inc     dx                      ;   set high word of return code
  243.         mov     ah, 12h                 ;   and use Function 12h
  244.         .ENDIF
  245.         int     16h                     ; Get Keyboard Flags
  246.         ret
  247.  
  248. GetShift ENDP
  249.  
  250.  
  251. ;* GetKeyClock - Waits for keystroke while updating time at specified location
  252. ;* on screen.
  253. ;*
  254. ;* Shows:   BIOS Interrupt - 16h, Functions 0 and 10h (Read Character)
  255. ;*                           16h, Functions 1 and 11h (Get Keyboard Status)
  256. ;*          DOS Functions - 2Ah (Get Date)
  257. ;*                          2Ch (Get Time)
  258. ;*
  259. ;* Uses:    vconfig - Video configuration structure (initialized
  260. ;*          by calling the GetVidConfig procedure)
  261. ;*
  262. ;* Params:  Row - Screen row for clock display
  263. ;*          Col - Screen column for clock display
  264. ;*
  265. ;* Return:  Short integer with key scan code in high byte and ASCII
  266. ;*          character code in low byte. Low byte is 0 for special
  267. ;*          keys (such as the "F" keys), which don't generate characters.
  268.  
  269.         .DATA
  270.         PUBLIC  datestr
  271. datestr BYTE    "  -  -     :  :  ", 0  ; Date/time string
  272.         .CODE
  273.  
  274. GetKeyClock PROC,
  275.         Row:WORD, Col:WORD
  276.  
  277.         LOCAL   service:BYTE
  278.  
  279.         INVOKE  GetShift                ; Check for extended keyboard
  280.         mov     service, 11h            ; Assume Function 11h
  281.         .IF     dx != 1                 ; If no extended keyboard,
  282.         mov     service, 1              ;   use Function 1
  283.         .ENDIF
  284.  
  285.         .WHILE  1
  286.         mov     ah, service
  287.         int     16h                     ; Get Keyboard Status
  288.         .BREAK  .IF !zero?              ; If no key yet, update clock
  289.  
  290. ; If not monochrome, color text, or black and white, skip clock update
  291. ; and poll keyboard again.
  292.  
  293.         .CONTINUE .IF (vconfig.mode != 7) \
  294.                    && (vconfig.mode != 3) \
  295.                    && (vconfig.mode != 2)
  296.  
  297. ; If 80-column text, get date and time from DOS before again
  298. ; polling keyboard, and display at upper right corner of screen.
  299.  
  300.         mov     ah, 2Ch                 ; Request time
  301.         int     21h                     ; Get Time
  302.         mov     dl, dh
  303.         push    dx                      ; Save seconds,
  304.         push    cx                      ;   minutes,
  305.         mov     cl, ch                  ;   and
  306.         push    cx                      ;   hours
  307.         mov     ah, 2Ah                 ; Request date
  308.         int     21h                     ; Get Date
  309.         sub     cx, 1900                ; Subtract century, CL = year
  310.         push    cx                      ; Save year,
  311.         push    dx                      ;   day,
  312.         mov     dl, dh                  ;   and
  313.         push    dx                      ;   month
  314.  
  315.         mov     cx, 6
  316.         sub     bx, bx
  317.  
  318.         .REPEAT
  319.         pop     ax                      ; Recover all 6 numbers in AL
  320.         aam                             ; Convert to unpacked BCD
  321.         xchg    al, ah                  ; Switch bytes for word move
  322.         or      ax, "00"                ; Make ASCII numerals
  323.         mov     WORD PTR datestr[bx], ax; Copy to string
  324.         add     bx, 3                   ;   at every third byte
  325.         .UNTILCXZ
  326.  
  327.         INVOKE  StrWrite, Row, Col, ADDR datestr
  328.         .ENDW                           ; Loop again for keypress
  329.  
  330.         mov     ah, service             ; 1 or 11h, depending on keybd
  331.         dec     ah                      ; Set AH to 0 or 10h
  332.         int     16h                     ; Get key to remove it from
  333.         ret                             ;   keyboard buffer
  334.  
  335. GetKeyClock ENDP
  336.  
  337.  
  338. ;* GetPSP - Gets address of Program Segment Prefix. For DOS 3.0 or higher.
  339. ;*
  340. ;* Shows:   DOS Function - 62h (Get PSP Address)
  341. ;*          Instruction - call
  342. ;*
  343. ;* Params:  None
  344. ;*
  345. ;* Return:  Short integer with PSP segment address
  346. ;*          or 0 if DOS version below 3.0
  347.  
  348. GetPSP  PROC
  349.  
  350.         INVOKE  GetVer                  ; Get DOS version number
  351.         .IF     ax >= 300               ; If DOS 3.0 or higher:
  352.         mov     ah, 62h                 ;   query DOS for PSP,
  353.         int     21h                     ;   get PSP Address,
  354.         mov     ax, bx                  ;   return in AX
  355.         .ELSE                           ; Else 2.0:
  356.         sub     ax, ax                  ; For version 2, return 0
  357.         .ENDIF
  358.         ret
  359.  
  360. GetPSP  ENDP
  361.  
  362.  
  363. ;* GetMem - Gets total size of memory and determines the largest amount of
  364. ;* unallocated memory available. GetMem invokes DOS Function 48h (Allocate
  365. ;* Memory) to request an impossibly large memory block. DOS denies the re-
  366. ;* quest, but returns instead the size of the largest block available. This
  367. ;* is the amount that GetMem returns to the calling program. See the WinOpen
  368. ;* procedure for an example of calling Function 48h to allocate unused memory.
  369. ;*
  370. ;* Shows:   BIOS Interrupt - 12h (Get Conventional Memory Size)
  371. ;*          Instructions - push     pop      ret
  372. ;*
  373. ;* Params:  None
  374. ;*
  375. ;* Return:  Long integer, high word = total memory in kilobytes (KB)
  376. ;*                        low word  = largest block of available memory (KB)
  377.  
  378. GetMem  PROC
  379.  
  380.         int     12h                     ; Get total memory in kilobytes
  381.         push    ax                      ; Save size of memory
  382.         mov     ah, 48h                 ; Request memory allocation
  383.         mov     bx, 0FFFFh              ; Ensure request is denied for
  384.                                         ;   impossibly large block
  385.         int     21h                     ; Get largest available block in BX
  386.         mov     ax, bx                  ; Copy to AX
  387.         mov     cl, 6                   ; Convert paragraphs to kilobytes by
  388.         shr     ax, cl                  ;   dividing by 64
  389.         pop     dx                      ; Recover total in DX
  390.         ret                             ; Return long integer DX:AX
  391.  
  392. GetMem  ENDP
  393.  
  394.  
  395. ;* VeriPrint - Checks if LPT1 (PRN) is available.
  396. ;*
  397. ;* Shows:   BIOS Interrupt - 17h (Parallel Port Printer Driver)
  398. ;*
  399. ;* Params:  None
  400. ;*
  401. ;* Return:  Short integer, 1 for yes or 0 for no
  402.  
  403. VeriPrint PROC
  404.  
  405.         mov     ah, 2                   ; Check printer status for
  406.         sub     dx, dx                  ;   parallel printer (port 0)
  407.         int     17h
  408.         xchg    dx, ax                  ; Put 0 (for error) in AX
  409.  
  410. ; If all error bits are off and both operation bits are on, return 1
  411.  
  412.         .IF     !(dh & 00101001y) && (dh & 10010000y)
  413.         inc     ax                      ; Return 1
  414.         .ENDIF
  415.         ret
  416.  
  417. VeriPrint ENDP
  418.  
  419.  
  420. ;* IntToAsc - Converts integer to ASCII string. This procedure is useful
  421. ;* only for assembly language and is not intended to be callable by C.
  422. ;*
  423. ;* Shows:   Instructions - aam     xchg
  424. ;*
  425. ;* Entry:   AX = integer (9999 max)
  426. ;*
  427. ;* Return:  DX:AX = 4-digit ASCII number
  428.  
  429. IntToAsc PROC
  430.  
  431.         cwd                             ; Zero DX register
  432.         mov     cx, 100                 ; Divide AX by 100, yields
  433.         div     cx                      ;   AX=quotient, DX=remainder
  434.         aam                             ; Make digits unpacked BCD
  435.         or      ax, "00"                ; Convert to ASCII
  436.         xchg    ax, dx                  ; Do same thing for DX
  437.         aam
  438.         or      ax, "00"
  439.         ret                             ; Return DX:AX = ASCII number
  440.  
  441. IntToAsc ENDP
  442.  
  443.  
  444. ;* VeriAnsi - Checks for ANSI driver by writing ANSI sequence to report
  445. ;* cursor position. If report compares with position returned from
  446. ;* GetCurPos procedure, then ANSI driver is operating.
  447. ;*
  448. ;* Shows:   DOS Functions - 06h (Direct Console I/O)
  449. ;*                          0Ch (Flush Input Buffer and then Input)
  450. ;*
  451. ;* Params:  None
  452. ;*
  453. ;* Return:  Short integer, 1 for yes or 0 for no
  454.  
  455.         .DATA
  456.         PUBLIC report
  457. report  DB      ESCAPE, "[6n$"          ; ANSI Report Cursor sequence
  458.         .CODE
  459.  
  460. VeriAnsi PROC
  461.  
  462.         ; Get cursor position from BIOS
  463.         INVOKE  GetCurPos
  464.         mov     cx, ax                  ; Save it in CX
  465.         mov     dx, OFFSET report       ; ANSI string to get position
  466.         mov     ah, 9                   ; Request DOS String Output
  467.         int     21h                     ; Write ANSI escape sequence
  468.  
  469.         mov     ah, 6                   ; Skip Esc character in
  470.         mov     dl, 0FFh                ;   keyboard buffer
  471.         int     21h
  472.         jz      e_exit                  ; If no key, ANSI not loaded
  473.         mov     ah, 6                   ; Skip '[' character
  474.         int     21h
  475.         jz      e_exit                  ; If no key, ANSI not loaded
  476.         mov     ah, 6                   ; Get 1st digit of cursor row
  477.         int     21h
  478.         jz      e_exit                  ; If no key, ANSI not loaded
  479.         mov     bh, al                  ; Store in BH
  480.         mov     ah, 6                   ; Get 2nd digit of cursor row
  481.         int     21h
  482.         jz      e_exit                  ; If no key, ANSI not loaded
  483.         mov     bl, al                  ; Store in BL
  484.         mov     al, ch                  ; Get original row # in AL
  485.         cbw                             ; AX = row # from GetCurPos
  486.         inc     ax                      ; Add 1 to it
  487.         call    IntToAsc                ; Make ASCII digits
  488.         cmp     ax, bx                  ; ANSI and BIOS reports match?
  489.         jne     e_exit                  ; No?  Then ANSI not loaded
  490.  
  491.         mov     ax, 0C06h               ; Flush remaining ANSI keys
  492.         mov     dl, 0FFh                ;   from buffer
  493.         int     21h
  494.         mov     ax, 1                   ; Set 1 for true
  495.         jmp     exit                    ;   and exit
  496. e_exit:
  497.         sub     ax, ax                  ; Set 0 return code if no
  498. exit:
  499.         ret                             ;   ANSI driver installed
  500.  
  501. VeriAnsi ENDP
  502.  
  503.  
  504. ;* VeriCop - Checks for coprocessor.
  505. ;*
  506. ;* Shows:   BIOS Interrupt - 11h (Get Equipment Configuration)
  507. ;*
  508. ;* Params:  None
  509. ;*
  510. ;* Return:  Short integer, 1 for yes or 0 for no
  511.  
  512. VeriCop PROC
  513.  
  514.         int     11h                     ; Check peripherals
  515.         test    al, 2                   ; Coprocessor?
  516.         mov     ax, 0                   ; Assume no, don't alter flags
  517.         .IF     !zero?
  518.         inc     ax                      ; Set to 1
  519.         .ENDIF
  520.         ret
  521.  
  522. VeriCop ENDP
  523.  
  524.  
  525. ;* SetLineMode - Sets line mode for EGA or VGA.
  526. ;*
  527. ;* Shows:   BIOS Interrupt - 10h, Function 11h (Character Generator Interface)
  528. ;*                           10h, Function 12h (Video Subsystem Configuration)
  529. ;*
  530. ;* Uses:    vconfig - Video configuration structure (initialized
  531. ;*          by calling the GetVidConfig procedure)
  532. ;*
  533. ;* Params:  Line - Requested line mode (25, 43, or 50)
  534. ;*
  535. ;* Return:  Short integer with error code
  536. ;*          0 if successful
  537. ;*          1 if error
  538.  
  539. SetLineMode PROC,
  540.         Line:WORD
  541.  
  542.         .IF     vconfig.adapter >= EGA  ; If EGA or VGA:
  543.         mov     ax, Line                ; Check for valid parameter
  544.         cmp     al, 25
  545.         je      line25
  546.         cmp     al, 43
  547.         je      line43
  548.         cmp     al, 50
  549.         je      line50
  550.         jmp     e_exit                  ; If not 25, 43, or 50, exit w/ error
  551. line25:
  552.         mov     al, 11h                 ; Set for EGA 25-line mode
  553.         cmp     vconfig.adapter, EGA    ; EGA?
  554.         je      linemode                ; Yes?  Continue
  555.         mov     ax, 1202h               ; No?  Function 12h for VGA
  556.         mov     bl, 30h                 ; AL = 2 for 400 scan lines
  557.         int     10h                     ; Reset to 400 scan lines
  558.         mov     ax, 0003                ; Reset mode (Function 0)
  559.         int     10h                     ;   to mode 3 (80-col text)
  560.         mov     al, 14h                 ; Request 8x16 char matrix
  561.         jmp     linemode
  562. line43:
  563.         mov     al, 12h                 ; Set for EGA 43-line mode
  564.         cmp     vconfig.adapter, EGA    ; EGA?
  565.         je      linemode                ; Yes?  Continue
  566.         mov     ax, 1201h               ; No?  Function 12h for VGA
  567.         mov     bl, 30h                 ; AL = 1 for 350 scan lines
  568.         int     10h                     ; Reset to 350 scan lines
  569.         mov     ax, 0003                ; Reset mode (Function 0)
  570.         int     10h                     ;   to mode 3 (80-col text)
  571.         mov     al, 12h                 ; Request 8x8 character matrix
  572.         jmp     linemode
  573. line50:
  574.         cmp     vconfig.adapter, VGA    ; VGA?
  575.         jne     e_exit                  ; No?  Exit with error
  576.         mov     ax, 1202h               ; Yes?  Function 12h
  577.         mov     bl, 30h                 ; AL = 2 for 400 scan lines
  578.         int     10h                     ; Reset to 400 scan lines
  579.         mov     ax, 0003                ; Reset mode (Function 0)
  580.         int     10h                     ;   to mode 3 (80-col text)
  581.         mov     al, 12h                 ; Request 8x8 character matrix
  582. linemode:
  583.         sub     bl, bl                  ; Use table 0
  584.         mov     ah, 11h                 ; Request Function 11h
  585.         int     10h                     ; Set new line mode
  586.  
  587.         mov     ah, 12h                 ; Select alternate print
  588.         mov     bl, 20h                 ;   screen for EGA and VGA
  589.         int     10h
  590.  
  591.         cmp     vconfig.adapter, VGA    ; VGA?
  592.         je      exit                    ; Yes?  Then exit
  593.         cmp     Line, 12h               ; If EGA 43-line mode, set
  594.         je      port                    ;   cursor through port to
  595.                                         ;   avoid cursor emulation bug
  596.  
  597.         ; Set normal cursor size, pass top and bottom scan lines
  598.         INVOKE  SetCurSize, 6, 7
  599.         jmp     exit
  600. port:
  601.         mov     dx, 03D4h               ; Video controller address
  602.         mov     ax, 060Ah               ; Set AH = 06h (cursor start)
  603.                                         ;     AL = 0Ah (register #)
  604.         out     dx, ax                  ; Update port
  605.         mov     ax, 000Bh               ; Set AH = 00h (cursor end)
  606.                                         ;     AL = 0Bh (register #)
  607.         out     dx, ax                  ; Update port
  608.         jmp     exit                    ; Normal exit
  609.         .ENDIF  ; EGA or VGA
  610. e_exit:
  611.         mov     ax, 1                   ; Set error code
  612.         jmp     exit2
  613. exit:
  614.         sub     ax, ax                  ; Clear error code
  615. exit2:
  616.         ret
  617.  
  618. SetLineMode ENDP
  619.  
  620.  
  621. ;* Pause - Waits for specified number of clocks to elapse, then returns.
  622. ;*
  623. ;* Shows:   BIOS Interrupt - 1Ah, Function 0 (Real-Time Clock Driver)
  624. ;*          Operators - LOCAL     []
  625. ;*
  626. ;* Params:  Duration - Desired duration in clocks, where
  627. ;*                     18 clocks = approx 1 second
  628. ;*
  629. ;* Return:  None
  630.  
  631. Pause   PROC,
  632.         Duration:WORD
  633.  
  634.         LOCAL tick:DWORD
  635.  
  636.         sub     ah, ah
  637.         int     1Ah                     ; Get Clock Count in CX:DX
  638.         add     dx, Duration            ; Add pause time to it
  639.         adc     cx, 0
  640.         mov     WORD PTR tick[0], dx    ; Result is target time;
  641.         mov     WORD PTR tick[2], cx    ;   keep in local variable
  642.  
  643.         .REPEAT
  644.         int     1Ah                     ; Poll clock until target time
  645.         .UNTIL  (dx >= WORD PTR tick[0]) || (cx >= WORD PTR fileinfo.time[2])
  646.         ret
  647.  
  648. Pause   ENDP
  649.  
  650.  
  651. ;* Sound - Sounds speaker with specified frequency and duration.
  652. ;*
  653. ;* Shows:   Instructions - in           out
  654. ;*
  655. ;* Params:  Freq - Desired frequency of sound in hertz
  656. ;*          Duration - Desired duration in clocks, where
  657. ;*                     18 clocks = approx 1 second
  658. ;*
  659. ;* Return:  None
  660.  
  661. Sound   PROC,
  662.         Freq:WORD, Duration:WORD
  663.  
  664.         mov     al, 0B6h                ; Initialize channel 2 of
  665.         out     43h, al                 ;   timer chip
  666.         mov     dx, 12h                 ; Divide 1,193,182 hertz
  667.         mov     ax, 34DEh               ;   (clock frequency) by
  668.         div     Freq                    ;   desired frequency
  669.                                         ; Result is timer clock count
  670.         out     42h, al                 ; Low byte of count to timer
  671.         mov     al, ah
  672.         out     42h, al                 ; High byte of count to timer
  673.         in      al, 61h                 ; Read value from port 61h
  674.         or      al, 3                   ; Set first two bits
  675.         out     61h, al                 ; Turn speaker on
  676.  
  677.         ; Pause, pass duration of delay
  678.         INVOKE  Pause, Duration
  679.  
  680.         in      al, 61h                 ; Get port value
  681.         xor     al, 3                   ; Kill bits 0-1 to turn
  682.         out     61h, al                 ;   speaker off
  683.         ret
  684.  
  685. Sound   ENDP
  686.  
  687.  
  688. ;* WriteTTY - Displays ASCIIZ string at cursor position, in either text
  689. ;* or graphics mode.
  690. ;*
  691. ;* Shows:   BIOS Interrupt - 10h, Function 0Eh (Write Character in TTY Mode)
  692. ;*
  693. ;* Uses:    vconfig - Video configuration structure (initialized
  694. ;*          by calling the GetVidConfig procedure)
  695. ;*
  696. ;* Params:  Sptr - Pointer to ASCIIZ string
  697. ;*          icolor - Color index (for graphics mode only)
  698. ;*
  699. ;* Return:  None
  700.  
  701. WriteTTY PROC USES ds si,
  702.         Sptr:PBYTE, icolor:WORD
  703.  
  704.         mov     bx, icolor              ; BL = color index
  705.         mov     bh, vconfig.dpage       ; BH = current display page
  706.         LoadPtr ds, si, Sptr
  707.         mov     cx, -1                  ; Set loop counter to maximum
  708.         mov     ah, 14                  ; Function 14
  709.  
  710.         .REPEAT
  711.         lodsb                           ; Get character from string
  712.         .BREAK .IF al == 0              ; Exit if NULL string terminator
  713.         int     10h                     ; No?  Display, advance cursor
  714.         .UNTILCXZ
  715.  
  716.         ret
  717.  
  718. WriteTTY ENDP
  719.  
  720.  
  721. ;* Colors - Alters screen colors within a specified area by using bit
  722. ;* or move operations on display attribute bytes in video memory.
  723. ;*
  724. ;* Shows:   Instructions - not     rol     ror     and     xor     or
  725. ;*
  726. ;* Params:  Logic - Code number, 0 = NOT    2 = ROR     4 = XOR    6 = MOV
  727. ;*                               1 = ROL    3 = AND     5 = OR
  728. ;*          Attr - Attribute mask
  729. ;*          Row1 - Row at top of window
  730. ;*          Col1 - Column at left edge of window
  731. ;*          Row2 - Row at bottom of window
  732. ;*          Col2 - Column at right edge of window
  733. ;*
  734. ;* Return:  None
  735.  
  736. Colors  PROC USES ds si,
  737.         Logic:WORD, Attr:WORD, Row1:WORD, Col1:WORD, Row2:WORD, Col2:WORD
  738.  
  739.         GetVidOffset Row1, Col1         ; Get offset in video segment
  740.         inc     ax
  741.         mov     si, ax                  ; SI = offset for 1st attr byte
  742.         mov     bx, Row2
  743.         sub     bx, Row1
  744.         inc     bx                      ; BX = number of window rows
  745.         mov     cx, Col2
  746.         sub     cx, Col1
  747.         inc     cx                      ; CX = number of columns
  748.  
  749.         mov     ds, vconfig.sgmnt       ; DS = video segment
  750.         mov     ax, Attr                ; AL = mask for and, xor, and or
  751.  
  752.         .REPEAT
  753.         push    si                      ; Save ptr to start of line
  754.         push    cx                      ;   and number of columns
  755.  
  756. ; Disable CGA video prior to memory access to avoid screen snow. (See the
  757. ; WinOpen and StrWrite procedures for further discussions on CGA snow.)
  758.  
  759.         .IF     vconfig.adapter == CGA  ; If CGA adapter:
  760.         INVOKE  DisableCga              ; Yes?  Disable video
  761.         .ENDIF
  762.  
  763.         cmp     Logic, 1                ; Rotate left?
  764.         jl      c_not                   ; If less, do NOT
  765.         je      c_rol                   ; If equal, do ROL
  766.         cmp     Logic, 3                ; And?
  767.         jl      c_ror                   ; If less, do ROR
  768.         je      c_and                   ; If equal, do AND
  769.         cmp     Logic, 5                ; Or?
  770.         jl      c_xor                   ; If less, do XOR
  771.         je      c_or                    ; If equal, do OR
  772. c_mov:
  773.         mov     BYTE PTR [si], al       ; MOV attr parameter
  774.         add     si, 2                   ;   into attribute byte
  775.         loop    c_mov
  776.         jmp     c_done
  777. c_or:
  778.         or      BYTE PTR [si], al       ; OR with attr parameter
  779.         add     si, 2
  780.         loop    c_or
  781.         jmp     c_done
  782. c_xor:
  783.         xor     BYTE PTR [si], al       ; XOR with attr parameter
  784.         add     si, 2
  785.         loop    c_xor
  786.         jmp     c_done
  787. c_and:
  788.         and     BYTE PTR [si], al       ; AND with attr parameter
  789.         add     si, 2
  790.         loop    c_and
  791.         jmp     c_done
  792. c_ror:
  793.         ror     BYTE PTR [si], 1        ; Rotate right 1 bit
  794.         add     si, 2
  795.         loop    c_ror
  796.         jmp     c_done
  797. c_rol:
  798.         rol     BYTE PTR [si], 1        ; Rotate left 1 bit
  799.         add     si, 2
  800.         loop    c_rol
  801.         jmp     c_done
  802. c_not:
  803.         not     BYTE PTR [si]           ; Flip bits
  804.         add     si, 2
  805.         loop    c_not
  806. c_done:
  807.         .IF     vconfig.adapter == CGA  ; If CGA,
  808.         INVOKE  EnableCga               ;   reenable CGA video
  809.         .ENDIF
  810.  
  811.         pop     cx                      ; Recover number of columns
  812.         pop     si                      ; Recover offset for start of line
  813.         add     si, 160                 ; Point to start of next line
  814.         dec     bx                      ; Decrement row counter
  815.         .UNTIL  zero?                   ; Loop while rows remain
  816.         ret
  817.  
  818. Colors  ENDP
  819.  
  820.  
  821. ;* Exec - Executes a child process.  Exec handles the usual chores associated
  822. ;* with spawning a process:  (1) parsing the command line tail and loading the
  823. ;* FCBs with the first two arguments; (2) setting and restoring the vectors
  824. ;* for Interrupts 1Bh, 23h, and 24h; and (3) querying DOS for the child's
  825. ;* return code.
  826. ;*
  827. ;* Shows:   DOS Functions - 29h (Parse Filename)
  828. ;*                          25h (Set Interrupt Vector)
  829. ;*                          35h (Get Interrupt Vector)
  830. ;*                          4Bh (Execute Program)
  831. ;*                          4Dh (Get Return Code)
  832. ;*
  833. ;* Params:  Spec - Pointer to ASCIIZ specification for program file
  834. ;*                 (must include .COM or .EXE extension)
  835. ;*          Block - Pointer to parameter block structure
  836. ;*          CtrBrk - Pointer to new CTRL+BREAK (Interrupt 1Bh) handler
  837. ;*          CtrlC - Pointer to new CTRL+C (Interrupt 23h) handler
  838. ;*          Criterr - Pointer to new Critical Error (Interrupt 24h) handler
  839. ;*
  840. ;* Return:  Short integer with child return code, or -1 for EXEC error
  841.  
  842. Exec    PROC USES ds si di,
  843.         Spec:PBYTE, Block:PPARMBLK, CtrBrk:PTR FAR,
  844.         CtrlC:PTR FAR, Criterr:PTR FAR
  845.  
  846.         Vector 1Bh, Old1Bh, CtrBrk      ; Save, replace Int 1Bh vector
  847.         Vector 23h, Old23h, CtrlC       ; Save, replace Int 23h vector
  848.         Vector 24h, Old24h, Criterr     ; Save, replace Int 24h vector
  849.  
  850.         LoadPtr ds, bx, Block           ; Point DS:BX to parameter block
  851.         push    ds                      ; Save segment address
  852.         les     di, (PARMBLK PTR [bx]).fcb1    ; Point ES:DI to first FCB
  853.         lds     si, (PARMBLK PTR [bx]).taddr   ; Point DS:SI to command-line
  854.                                                ;   tail
  855.         inc     si                      ; Skip over count byte
  856.  
  857.         mov     ax, 2901h               ; Set AH to request Function 29h
  858.                                         ; AL = flag to skip leading blanks
  859.         int     21h                     ; Parse command-line into first FCB
  860.         pop     es                      ; Recover seg addr of parameter block
  861.         les     di, (PARMBLK PTR es:[bx]).fcb2   ; Point ES:DI to second FCB
  862.         mov     ax, 2901h               ; Request DOS Function #29h again
  863.         int     21h                     ; Parse command-line into second FCB
  864.  
  865.         push    bp                      ; Save only important register
  866.         mov     WORD PTR cs:OldStk[0], sp
  867.         mov     WORD PTR cs:OldStk[2], ss
  868.         LoadPtr es, bx, Block           ; ES:BX points to param block
  869.         LoadPtr ds, dx, Spec            ; DS:DX points to path spec
  870.         mov     ax, 4B00h               ; AH = DOS Function 4Bh
  871.                                         ; AL = 0 for load and execute
  872.         int     21h                     ; Execute Program
  873.         mov     sp, WORD PTR cs:OldStk[0] ; Reset stack pointers
  874.         mov     ss, WORD PTR cs:OldStk[2]
  875.         pop     bp                      ; Recover saved register
  876.  
  877. ; Restore vectors for Interrupts 1Bh, 23h, and 24h.
  878.  
  879.         mov     ax, 251Bh               ; AH = DOS Function 25h
  880.                                         ; AL = interrupt number
  881.         lds     dx, cs:Old1Bh           ; DS:DX = original vector
  882.         int     21h                     ; Set Interrupt 1Bh Vector
  883.         mov     al, 23h                 ; AL = interrupt number
  884.         lds     dx, cs:Old23h           ; DS:DX = original vector
  885.         int     21h                     ; Set Interrupt 23h Vector
  886.         mov     al, 24h                 ; AL = interrupt number
  887.         lds     dx, cs:Old24h           ; DS:DX = original vector
  888.         int     21h                     ; Set Interrupt 24h Vector
  889.  
  890.         mov     ax, -1                  ; Set error code
  891.         .IF     !carry?                 ; If no EXEC error:
  892.         mov     ah, 4Dh                 ; Request child's code
  893.         int     21h                     ; Get Return Code
  894.         sub     ah, ah                  ; Make short integer
  895.         .ENDIF
  896.         ret
  897.  
  898. Old1Bh  FPVOID  ?                       ; Keep vectors for Interrupts
  899. Old23h  FPVOID  ?                       ;   1Bh, 23h, and 24h in code
  900. Old24h  FPVOID  ?                       ;   segment, but nonexecutable
  901. OldStk  FPVOID  ?                       ; Keep stack pointer
  902.  
  903. Exec    ENDP
  904.  
  905.  
  906. ;* BinToHex - Converts binary word to 6-byte hexadecimal number in
  907. ;* ASCIIZ string. String is right justified and includes "h" radix.
  908. ;*
  909. ;* Shows:   Instruction - xlat
  910. ;*
  911. ;* Params:  Num - Number to convert to hex string
  912. ;*          Sptr - Pointer to 6-byte string
  913. ;*
  914. ;* Return:  None
  915.  
  916.         .DATA
  917. hex     BYTE    "0123456789ABCDEF"      ; String of hex numbers
  918.  
  919.         .CODE
  920. BinToHex PROC USES di,
  921.         Num:WORD, Sptr:PBYTE
  922.  
  923.         LoadPtr es, di, Sptr            ; Point ES:DI to 6-byte string
  924.         mov     bx, OFFSET hex          ; Point DS:BX to hex numbers
  925.         mov     ax, Num                 ; Number in AX
  926.         mov     cx, 2                   ; Loop twice for two bytes
  927.  
  928.         .REPEAT
  929.         xchg    ah, al                  ; Switch bytes
  930.         push    ax                      ; Save number
  931.         shr     al, 1                   ; Shift high nibble to low
  932.         shr     al, 1
  933.         shr     al, 1
  934.         shr     al, 1
  935.         xlat                            ; Get equivalent ASCII number in AL
  936.         stosb                           ; Copy to 6-byte string, increment DI
  937.         pop     ax                      ; Recover number
  938.         push    ax                      ; Save it again
  939.         and     al, 00001111y           ; Mask out high nibble
  940.         xlat                            ; Get equivalent ASCII number in AL
  941.         stosb                           ; Copy to 6-byte string, increment DI
  942.         pop     ax                      ; Recover number
  943.         .UNTILCXZ                       ; Do next byte
  944.         mov     ax, 'h'                 ; Put null, 'h' radix in AX
  945.         stosw                           ; Copy to last two bytes in string
  946.         ret
  947.  
  948. BinToHex ENDP
  949.  
  950.  
  951. ;* NewBlockSize - Adjusts size of allocated memory block.
  952. ;*
  953. ;* Shows:   DOS Function - 4Ah (Resize Memory Block)
  954. ;*
  955. ;* Params:  Adr - Segment address of block
  956. ;*          Resize - Requested block size in paragraphs
  957. ;*
  958. ;* Return:  Short integer error code
  959. ;*          0 if successful
  960. ;*          1 if error
  961.  
  962. NewBlockSize PROC,
  963.         Adr:WORD, Resize:WORD
  964.  
  965.         mov     ax, Adr                 ; Get block address
  966.         mov     es, ax                  ; Point ES to block
  967.         mov     bx, Resize              ; New block size
  968.         mov     ah, 4Ah                 ; Function number
  969.         int     21h                     ; Resize Memory Block
  970.         ret
  971.  
  972. NewBlockSize ENDP
  973.  
  974.  
  975. ;* Initialize - Initializes global variables _psp and _env, which are defined
  976. ;* in the DEMO.INC include file. If used with a DOS version less than 3.0,
  977. ;* this procedure will not produce valid results unless it is called before
  978. ;* changing the ES register. This is because at program entry ES points to
  979. ;* the Program Segment Prefix (PSP).
  980. ;*
  981. ;* Params:  None
  982. ;*
  983. ;* Return:  None
  984.  
  985. Initialize PROC
  986.  
  987.         INVOKE  GetPSP                  ; Get segment address of PSP
  988.         .IF     ax == 0                 ; If less than DOS 3.0,
  989.         mov     es, ax                  ;   reload ES with PSP address
  990.         .ENDIF
  991.  
  992.         mov     _psp, es                ; Initialize variable with PSP address
  993.         mov     ax, es:[2Ch]            ; Get environment seg from PSP
  994.         mov     _env, ax                ; Store it
  995.         ret
  996.  
  997. Initialize ENDP
  998.  
  999.         END
  1000.